// 本来要进行的app定义，但是index.js里面也有一个同样的app定义所以直接把app写成参数形式在index.js里面也有一个同样的app定义所以直接把app写成参数形式在index.js里面直接把app引入就行了



// const express=require('express')
// const app=express()

module.exports = app => {
    const express = require("express")
    const jwt = require('jsonwebtoken')
    const auth = require(__dirname + '/../../middleware/auth')


    //子路由，用于实现具体的操作
    const route = express.Router({
        mergeParams: true
    })
    route.post('/', async (req, res) => {
        //异步函数，实现对数据的操作 需要操作的数据为：req.body.data        
        const body = await req.model.create(req.body)
        res.send(body)
    })
    route.get('/', async (req, res) => {
        //查询集合并返回
        //populate('关联的字段')：函数作用:用关联字段（要先在model里面先约束关联字段）取出有关关联字段的文档的信息--以字段取文档：在这里设置了parent为关联字段，所以可以取出关联parent字段的文档的所有字段信息返回在parent中
        const body = await req.model.find().populate('parent')
        res.send(body)
    })
    //获取某个详情页信息的接口
    route.get('/:id', async (req, res) => {
        //通过id查找——findById（'id'） id在req.parmas.id里面
        const body = await req.model.findById(req.params.id)
        res.send(body)
    })
    route.put('/:id', async (req, res) => {
        //根据id值进行update
        const body = await req.model.findByIdAndUpdate(req.body._id, req.body)
        res.send(body)
    })
    route.delete('/:id', async (req, res) => {
        //根据id值进行删除
        const body = await req.model.findByIdAndDelete(req.params.id, req.body)
        res.send(body)
    })

    //采用中间件的形式来处理model，这样在每次进行请求的时候就会自动进行model的映射
    app.use('/admin/api/rest/:resource', auth('token'), async (req, res, next) => {
        //复数转单数且符合类名规则
        const modelname = require('inflection').classify(req.params.resource)
        //model 如果用的是const格式的话route是使用不到的，中间件只会共享req和res数据 所以应该改为req.model
        //操作完中间件之后就多了一个req.model数据的,他指向的是当前请求数据的model
        //中间件的用法，在减少同样的操作，使冗余变少
        req.model = require(__dirname + `/../../model/${modelname}`)
        //中间件要加next()函数
        next()
    }, route)

    const multer = require('multer')
    //保存的地址
    const upload = multer({ dest: __dirname + '/../../upload' })
    //资源挂载
    app.use('/upload', express.static(__dirname + '/../../upload'))
    //接口调用
    app.post('/admin/api/upload', upload.single('file'), async (req, res) => {
        const file = req.file
        //拼写出url
        file.url = `http://47.104.164.246/upload/${file.filename}`
        res.send(file)
    })

    app.post('/admin/api/login', async (req, res) => {
        // const token = jwt.sign({ id: '625a5594aaa7e625c99a52b9' }, app.get('secret'))
        // res.send({ token, mes: '欢迎回来 ' })
        //结构赋值  把等号右边的值传递给左边的结构值，前提是右边的数据格式要和左边的相同  和组件提取模块是相同的，从组件中提取相同的module 值 const{a} =require('mokuai')意即从这个组件提取a模块
        const { username, password } = req.body
        //这里结构赋值的结果就是 req.body.username=username  |req.body.password.password=password 
        //1.根据用户名找用户 不存在=>用户名不存在
        //1.1引入管理员用户模型
        const model = require(__dirname + '/../../model/AdminUser')
        //1.2找用户-只找一条：所以要避免用户名重名问题，要在数据库模型进行限制——对username字段添加限制：unique:true  （注意涉及到数据库CRUD操作要用异步形式）
        // 这里建值重复,可以简写 username <=> username:username
        //由于在设置模型时设置password默认不取，所以要在这里加个取password操作 ==> select（’+xx'）：加上xx数据  |   （'-xx'）：减去xx[字段名]数据
        const reson = await model.findOne({ username }).select('+password')
        //1.3用户不存在=>res=null ？存在=>res=object
        if (!reson) {
            //1.3.1不存在用户   status(numbers)=>发送状态码:目的是让前端知道不是正常的200状态
            res.status(404).send({ message: '用户不存在' })
            //ps:对于返回状态码和数据，在前端响应要在axioshttp1设置那里加个响应拦截器 
        }
        //2.校验密码(注意前面在注册的时候密码已经被加密存储在数据库了)  不匹配=>密码错误)
        //2.1之前在模型里面用bcryptjs模块对数据进行加密因此要用模块对密码进行比较校验
        //(明文：密文)=>{return bool}  密文已经通过查找的形式把文档存储reson里面了==> 以后要找某个文档里面的某一个字段，直接把整个文档给找出来然后通过对象的形式找具体字段的数据
        if (!require('bcryptjs').compareSync(password, reson.password)) {
            //2.1.5密码不正确情况 返回错误响应
            res.status(404).send({
                message: '密码不正确'
            })
        }
        //3.用户名和密码都正确：返回token
        //3.1 token的实现用jwt模块
        //3.2 jwt用sign(签名)方法生成token  参数：(需要加密的数据(任何形式的数据，数组对象字符串),密钥(用于加密解密，应该设置为全局性质的,在index.js设置), (token设置(可选):token有效期...什么什么的)  )
        const token = jwt.sign({ id: reson._id }, app.get('secret'))
        res.send({ token, mes: '欢迎回来 ' + reson.username })
    }

    )

    //在所有路由后面加个错误处理中间件 
    //接收http-assert抛出的错误，因为assert的错误信息存储在err.message里面不能正常在前端显示(前端显示要在response.data.message里)，所以要在这里把err.mseeag=>data.message
    app.use(async (err, req, res, next) => {
        res.status(err.status || 500).send({
            message: err.message
        })
    })


}
//注意async和await要成对出现
//数据库>集合>文档>字段